//
// Created by cube on 2020/10/22.
//

#ifndef COMPILERDOMEA1_MULTPLEX_H
#define COMPILERDOMEA1_MULTPLEX_H

#include <set>
#include <list>
#include <vector>
#include <mutex>

#include "NetBase.h"

namespace NetBase {
    class MultiplexAbstract {
    public:
        MultiplexAbstract(const int &count) {}

        virtual int server(long timeout = -1) { return 0; }

        virtual void addSocket(int socket) {}

        virtual void eraseSocket(int socket) {}

        virtual void close() {}
//    virtual bool containsSocket(int socket) {}
    protected:
        virtual void disConnect(int socket) {
            eraseSocket(socket);
            Base::net_close(socket);
        }

        virtual bool read(int socket) { return true; }

        virtual void read(int socket, int8_t *data, const uint32_t &len) {}
//    virtual void write(int socket){}
    };

    class Select_Multplex : public MultiplexAbstract {
    public:
        using MultiplexAbstract::MultiplexAbstract;

        int server(long timeout = -1) override;

        void addSocket(int socket) override;

        void eraseSocket(int socket) override;

        void close() override;

    private:
        int __select_socket;
        fd_set fd_read;
//        fd_set fd_write;
//        fd_set fd_exp;
        std::set<int> __sockets;
        std::mutex __mutex;
    };

#if __linux && SYS_epoll_create

    class Epoll_Multplex : public MultiplexAbstract {
    public:
        Epoll_Multplex(const int &count);

        virtual ~Epoll_Multplex() { delete __events; }

        int server(long timeout = -1) override;

        void addSocket(int socket) override;

        void eraseSocket(int socket) override;

        void close() override;

    protected:
        void toWrite(int socket);

        void toRead(int socket);

    private:
        int __epoll_socket;
        epoll_event __event;
        epoll_event *__events;
        int __event_count;
    };

#endif

#if WIN32
    class IOCP_Multplex : public MultiplexAbstract {
        protected:
            typedef struct tagPER_HANDLE_DATA{
                SOCKET socket;
                SOCKADDR_STORAGE addr;
            } PER_HANDLE_DATA,*LPPER_HANDLE_DATA;
            typedef struct tagPER_IO_DATA{
                OVERLAPPED overlapped;
                WSABUF  databuf;
                char    buffer[1024];
                int     operationtype;
            } PER_IO_DATA,*LPPER_IO_DATA;
        public:
            IOCP_Multplex(const int& count);
            int server(long timeout = -1)override;
            void addSocket(int socket)override;
            void eraseSocket(int socket)override{}
        protected:
            void disConnect(int socket)override{}
        private:
            HANDLE __iocp_socket;
            LPPER_HANDLE_DATA   perHandleData = nullptr;
            LPPER_IO_DATA       perIoData = nullptr;
            LPOVERLAPPED        lpoverlapped;
            DWORD               datasize;
        };
#endif

#if __linux
#if SYS_epoll_create
    typedef Epoll_Multplex Multplex;
#elif
    typedef Select_Multplex Multplex;
#endif
#elif WIN32
    typedef Select_Multplex Multplex;
    //    typedef IOCP_Multplex Multplex;
#endif

}

#endif //COMPILERDOMEA1_MULTPLEX_H
